
package com.hlkj.pay.app.order.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.common.constants.MqConstant;
import com.hlkj.pay.config.ExtRocketMQTemplate;
import com.hlkj.pay.dto.common.OrderStatusDto;
import com.hlkj.pay.dto.merchant.MerchantAccessDto;
import com.hlkj.pay.dto.order.OrderFundDto;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.gateway.order.IChannelPaymentGateway;
import com.hlkj.pay.gateway.order.IOrderNotifyGateway;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAccessInfoDO;
import com.hlkj.pay.infrastructure.model.order.*;
import com.hlkj.pay.infrastructure.model.payment.MerchantPaymentDO;
import com.hlkj.pay.infrastructure.model.payment.MerchantPaymentDetailDO;
import com.hlkj.pay.service.order.IOrderNotifyService;
import com.hlkj.pay.service.order.IPayOrderFundService;
import com.hlkj.pay.service.order.IPayOrderService;
import com.hlkj.pay.service.order.IRefundOrderService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * @author HlpayTeam
 * @date 2024/10/10 15:30
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderNotifyProcessHandler {

    private final ExtRocketMQTemplate extRocketMQTemplate;

    private final IOrderNotifyGateway orderNotifyGateway;

    private final IOrderNotifyService orderNotifyService;

    private final IPayOrderService payOrderService;

    private final IRefundOrderService refundOrderService;

    private final IChannelPaymentGateway channelPaymentGateway;

    private final IPayOrderFundService payOrderFundService;

    public void notifyPayOrder(OrderStatusDto orderStatusDto, PayOrderDO payOrderDO, OrderNotifyDO orderNotifyDO) {
        if (payOrderDO == null) {
            log.info("支付订单数据错误 停止回调 payOrderNo:{}", orderNotifyDO.getId());
            return;
        }
        if (!checkNotifyUrl(payOrderDO.getNotifyUrl())) {
            log.info("支付订单未填写回调地址 停止回调 payOrderNo:{}", payOrderDO.getPayOrderNo());
            return;
        }
        List<OrderFundDetailDO> payOrderFundList = null;
        if (StringUtils.hasText(payOrderDO.getAcctInfoJson())) {
            payOrderFundList = payOrderFundService.queryPayAcctInfo(payOrderDO.getPayOrderNo());
        }
        OrderNotifyDO notifyDO = orderNotifyGateway.notifyPayOrder(payOrderDO, payOrderFundList);
        if (orderNotifyDO == null) {
            orderNotifyDO = orderNotifyService.queryDetail(payOrderDO.getPayOrderNo(), PayOrderEnums.ORDER_STATUS_TYPE.PAY_ORDER_STATUS.getCode());
        }
        if (orderNotifyDO == null) {
            notifyDO.setMchOrderNo(payOrderDO.getMchOrderNo());
            notifyDO.setPayOrderNo(payOrderDO.getPayOrderNo());
            notifyDO.setNotifyUrl(payOrderDO.getNotifyUrl());
            notifyDO.setSn(payOrderDO.getOrderSn());
            notifyDO.setAppId(payOrderDO.getAppId());
            notifyDO.setNotifyType(PayOrderEnums.ORDER_STATUS_TYPE.PAY_ORDER_STATUS.getCode());
            notifyDO.setNotifyNum(1);
            orderNotifyService.addOrderNotify(notifyDO);
        }
        else {
            notifyDO.setId(orderNotifyDO.getId());
            notifyDO.setNotifyNum(orderNotifyDO.getNotifyNum() + 1);
            orderNotifyService.updateOrderNotify(notifyDO);
        }
        if (payOrderDO.getNotifyState() == null || CommonEnum.YES_NO_TYPE.NO.getCode().equals(payOrderDO.getNotifyState())) {
            PayOrderDO updatePayOrderDO = new PayOrderDO();
            updatePayOrderDO.setId(payOrderDO.getId());
            updatePayOrderDO.setNotifyState(CommonEnum.YES_NO_TYPE.YES.getCode());
            payOrderService.updatePayOrder(updatePayOrderDO, payOrderDO.getPayOrderNo(), payOrderDO.getSn(), payOrderDO.getMchOrderNo());
        }
        if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(notifyDO.getNotifyState())) {
            if (orderStatusDto == null) {
                retryNotify(notifyDO.getPayOrderNo(), notifyDO.getNotifyNum(), PayOrderEnums.ORDER_STATUS_TYPE.PAY_ORDER_STATUS);
            }
            else {
                retryNotify(orderStatusDto);
            }
        }
    }

    public void notifyRefundOrder(OrderStatusDto orderStatusDto, RefundOrderDO refundOrderDO, OrderNotifyDO orderNotifyDO) {
        if (refundOrderDO == null) {
            log.info("退款订单数据错误 停止回调 payOrderNo:{}", orderNotifyDO.getId());
            return;
        }
        if (!checkNotifyUrl(refundOrderDO.getNotifyUrl())) {
            log.info("退款订单未填写回调地址 停止回调 payOrderNo:{}", refundOrderDO.getPayOrderNo());
            return;
        }
        OrderNotifyDO notifyDO = orderNotifyGateway.notifyRefundOrder(refundOrderDO);
        if (orderNotifyDO == null) {
            orderNotifyDO = orderNotifyService.queryDetail(refundOrderDO.getRefundOrderNo(), PayOrderEnums.ORDER_STATUS_TYPE.REFUND_STATUS.getCode());
        }
        if (orderNotifyDO == null) {
            notifyDO.setMchOrderNo(refundOrderDO.getMchRefundOrderNo());
            notifyDO.setPayOrderNo(refundOrderDO.getRefundOrderNo());
            notifyDO.setNotifyUrl(refundOrderDO.getNotifyUrl());
            notifyDO.setSn(refundOrderDO.getSn());
            notifyDO.setAppId(refundOrderDO.getAppId());
            notifyDO.setNotifyNum(1);
            notifyDO.setNotifyType(PayOrderEnums.ORDER_STATUS_TYPE.REFUND_STATUS.getCode());
            orderNotifyService.addOrderNotify(notifyDO);

        }
        else {
            notifyDO.setId(orderNotifyDO.getId());
            notifyDO.setNotifyNum(orderNotifyDO.getNotifyNum() + 1);
            orderNotifyService.updateOrderNotify(notifyDO);
        }
        if (refundOrderDO.getNotifyState() == null || CommonEnum.YES_NO_TYPE.NO.getCode().equals(refundOrderDO.getNotifyState())) {
            RefundOrderDO updatePayOrderDO = new RefundOrderDO();
            updatePayOrderDO.setId(refundOrderDO.getId());
            updatePayOrderDO.setNotifyState(CommonEnum.YES_NO_TYPE.YES.getCode());
            refundOrderService.updateRefundOrder(updatePayOrderDO, refundOrderDO.getRefundOrderNo(), refundOrderDO.getSn(), refundOrderDO.getMchRefundOrderNo());
        }
        if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(notifyDO.getNotifyState())) {
            if (orderStatusDto == null) {
                retryNotify(refundOrderDO.getRefundOrderNo(), notifyDO.getNotifyNum(), PayOrderEnums.ORDER_STATUS_TYPE.REFUND_STATUS);
            }
            else {
                retryNotify(orderStatusDto);
            }
        }
    }

    public void notifyPaymentOrder(OrderStatusDto orderStatusDto, MerchantPaymentDO merchantPaymentDO, MerchantPaymentDetailDO merchantPaymentDetailDO, OrderNotifyDO orderNotifyDO) {
        if (merchantPaymentDO == null) {
            log.info("转账订单数据错误 停止回调");
            return;
        }

        // 需要通知C端用户
        channelPaymentGateway.notifyChannel(merchantPaymentDO, merchantPaymentDetailDO);

        if (!checkNotifyUrl(merchantPaymentDO.getNotifyUrl())) {
            log.info("转账订单未填写回调地址 停止回调 paymentId:{}", merchantPaymentDO.getPaymentId());
            return;
        }
        OrderNotifyDO notifyDO = orderNotifyGateway.notifyPaymentOrder(merchantPaymentDO, merchantPaymentDetailDO);
        log.info("转账订单回调结果 detailPaymentId:{} notifyDO:{}", merchantPaymentDetailDO.getDetailPaymentId(), JsonUtils.toJsonString(notifyDO));
        if (orderNotifyDO == null) {
            orderNotifyDO = orderNotifyService.queryDetail(merchantPaymentDetailDO.getDetailPaymentId(), PayOrderEnums.ORDER_STATUS_TYPE.PAYMENT_ORDER_STATUS.getCode());
        }
        if (orderNotifyDO == null) {
            notifyDO.setMchOrderNo(merchantPaymentDetailDO.getMchOrderNo());
            notifyDO.setPayOrderNo(merchantPaymentDetailDO.getDetailPaymentId());
            notifyDO.setNotifyUrl(merchantPaymentDO.getNotifyUrl());
            notifyDO.setSn(merchantPaymentDO.getSn());
            notifyDO.setAppId(merchantPaymentDO.getAppId());
            notifyDO.setNotifyNum(1);
            notifyDO.setNotifyType(PayOrderEnums.ORDER_STATUS_TYPE.PAYMENT_ORDER_STATUS.getCode());
            orderNotifyService.addOrderNotify(notifyDO);
        }
        else {
            notifyDO.setId(orderNotifyDO.getId());
            notifyDO.setNotifyNum(orderNotifyDO.getNotifyNum() + 1);
            orderNotifyService.updateOrderNotify(notifyDO);
        }
        if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(notifyDO.getNotifyState())) {
            if (orderStatusDto == null) {
                retryNotify(merchantPaymentDetailDO.getDetailPaymentId(), notifyDO.getNotifyNum(), PayOrderEnums.ORDER_STATUS_TYPE.PAYMENT_ORDER_STATUS);
            }
            else {
                retryNotify(orderStatusDto);
            }
        }
    }

    public void notifyOrderFund(OrderStatusDto orderStatusDto, OrderFundDto orderFundDto, OrderNotifyDO orderNotifyDO) {
        if (orderFundDto == null) {
            log.info("分账订单状态数据错误 停止回调");
            return;
        }
        OrderFundDO orderFund = orderFundDto.getOrderFund();
        if (!checkNotifyUrl(orderFund.getNotifyUrl())) {
            log.info("分账订单未填写回调地址 停止回调 batchNo:{}", orderFund.getBatchNo());
            return;
        }
        PayOrderDO payOrderDO = payOrderService.queryPayOrder(orderFund.getPayOrderNo());
        orderFundDto.setMchOrderNo(payOrderDO.getMchOrderNo());
        OrderNotifyDO notifyDO = orderNotifyGateway.notifyOrderFund(orderFundDto);
        if (orderNotifyDO == null) {
            orderNotifyDO = orderNotifyService.queryDetail(orderFund.getBatchNo(), PayOrderEnums.ORDER_STATUS_TYPE.FUND_ORDER_STATUS.getCode());
        }
        if (orderNotifyDO == null) {
            notifyDO.setMchOrderNo(orderFund.getMchAcctOrderNo());
            notifyDO.setPayOrderNo(orderFund.getBatchNo());
            notifyDO.setNotifyUrl(orderFund.getNotifyUrl());
            notifyDO.setSn(orderFund.getSn());
            notifyDO.setAppId(orderFund.getAppId());
            notifyDO.setNotifyNum(1);
            notifyDO.setNotifyType(PayOrderEnums.ORDER_STATUS_TYPE.MERCHANT_ACCESS_SETTLE_STATUS.getCode());
            orderNotifyService.addOrderNotify(notifyDO);
        }
        else {
            notifyDO.setId(orderNotifyDO.getId());
            notifyDO.setNotifyNum(orderNotifyDO.getNotifyNum() + 1);
            orderNotifyService.updateOrderNotify(notifyDO);
        }
        if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(notifyDO.getNotifyState())) {
            if (orderStatusDto == null) {
                retryNotify(orderFundDto.getOrderFund().getBatchNo(), notifyDO.getNotifyNum(), PayOrderEnums.ORDER_STATUS_TYPE.FUND_ORDER_STATUS);
            }
            else {
                retryNotify(orderStatusDto);
            }
        }

    }

    public void notifyMerchantAccessSettle(OrderStatusDto orderStatusDto, OrderSettleDO accessSettleOrderDO, OrderNotifyDO orderNotifyDO) {
        if (accessSettleOrderDO == null) {
            log.info("商户结算状态数据错误 停止回调");
            return;
        }
        if (!checkNotifyUrl(accessSettleOrderDO.getNotifyUrl())) {
            log.info("商户结算状态订单未填写回调地址 停止回调 paymentId:{}", accessSettleOrderDO.getCashOrderNo());
            return;
        }
        OrderNotifyDO notifyDO = orderNotifyGateway.notifyMerchantAccessSettle(accessSettleOrderDO);
        if (orderNotifyDO == null) {
            orderNotifyDO = orderNotifyService.queryDetail(accessSettleOrderDO.getPayOrderNo(), PayOrderEnums.ORDER_STATUS_TYPE.MERCHANT_ACCESS_SETTLE_STATUS.getCode());
        }
        if (orderNotifyDO == null) {
            notifyDO.setMchOrderNo(accessSettleOrderDO.getCashOrderNo());
            notifyDO.setPayOrderNo(accessSettleOrderDO.getPayOrderNo());
            notifyDO.setNotifyUrl(accessSettleOrderDO.getNotifyUrl());
            notifyDO.setSn(accessSettleOrderDO.getSn());
            notifyDO.setAppId(accessSettleOrderDO.getAppId());
            notifyDO.setNotifyNum(1);
            notifyDO.setNotifyType(PayOrderEnums.ORDER_STATUS_TYPE.MERCHANT_ACCESS_SETTLE_STATUS.getCode());
            orderNotifyService.addOrderNotify(notifyDO);
        }
        else {
            notifyDO.setId(orderNotifyDO.getId());
            notifyDO.setNotifyNum(orderNotifyDO.getNotifyNum() + 1);
            orderNotifyService.updateOrderNotify(notifyDO);
        }
        if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(notifyDO.getNotifyState())) {
            if (orderStatusDto == null) {
                retryNotify(accessSettleOrderDO.getPayOrderNo(), notifyDO.getNotifyNum(), PayOrderEnums.ORDER_STATUS_TYPE.MERCHANT_ACCESS_SETTLE_STATUS);
            }
            else {
                retryNotify(orderStatusDto);
            }
        }
    }

    public void notifyMerchantAccess(OrderStatusDto orderStatusDto, MerchantAccessDto merchantAccessDto, OrderNotifyDO orderNotifyDO) {
        if (merchantAccessDto == null) {
            log.info("商户进件状态数据错误 停止回调");
            return;
        }
        MerchantAccessInfoDO merchantAccessInfo = merchantAccessDto.getMerchantAccessInfo();
        if (!checkNotifyUrl(merchantAccessInfo.getNotifyUrl())) {
            log.info("商户进件状态订单未填写回调地址 停止回调 paymentId:{}", merchantAccessInfo.getMchOrderNo());
            return;
        }
        OrderNotifyDO notifyDO = orderNotifyGateway.notifyMerchantAccess(merchantAccessDto);
        if (orderNotifyDO == null) {
            orderNotifyDO = orderNotifyService.queryDetail(merchantAccessInfo.getRequestId(), PayOrderEnums.ORDER_STATUS_TYPE.MERCHANT_ACCESS_STATUS.getCode());
        }
        if (orderNotifyDO == null) {
            notifyDO.setMchOrderNo(merchantAccessInfo.getMchOrderNo());
            notifyDO.setPayOrderNo(merchantAccessInfo.getRequestId());
            notifyDO.setNotifyUrl(merchantAccessInfo.getNotifyUrl());
            notifyDO.setSn(merchantAccessInfo.getSn());
            notifyDO.setAppId(merchantAccessInfo.getAppId());
            notifyDO.setNotifyNum(1);
            notifyDO.setNotifyType(PayOrderEnums.ORDER_STATUS_TYPE.MERCHANT_ACCESS_STATUS.getCode());
            orderNotifyService.addOrderNotify(notifyDO);
        }
        else {
            notifyDO.setId(orderNotifyDO.getId());
            notifyDO.setNotifyNum(orderNotifyDO.getNotifyNum() + 1);
            orderNotifyService.updateOrderNotify(notifyDO);
        }
        if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(notifyDO.getNotifyState())) {
            if (orderStatusDto == null) {
                retryNotify(merchantAccessInfo.getRequestId(), notifyDO.getNotifyNum(), PayOrderEnums.ORDER_STATUS_TYPE.MERCHANT_ACCESS_SETTLE_STATUS);
            }
            else {
                retryNotify(orderStatusDto);
            }
        }
    }

    public void retryNotify(String payOrderNo, Integer noticeNum, PayOrderEnums.ORDER_STATUS_TYPE orderStatusType) {
        OrderStatusDto orderStatusDto = new OrderStatusDto();
        orderStatusDto.setOrderNo(payOrderNo);
        orderStatusDto.setOrderStatusType(orderStatusType.getCode());
        try {
            orderStatusDto.setTotalConsumerCount(noticeNum);
            orderStatusDto.setDelaySendTime(System.currentTimeMillis());
            log.info("手动回调通知 payOrderNo:{},noticeNum:{}", payOrderNo, noticeNum);
            extRocketMQTemplate.sendDelay(noticeNum, MqConstant.MERCHANT_ORDER_NOTIFY_TOPIC, orderStatusDto);
        }
        catch (Exception e) {
            log.error("mq 发送异常:{}", e.getMessage(), e);
        }
    }

    public void retryNotify(OrderStatusDto orderStatusDto) {
        try {
            if (orderStatusDto.getTotalConsumerCount() == null) {
                orderStatusDto.setTotalConsumerCount(1);
            }
            if (orderStatusDto.getTotalConsumerCount() != null && orderStatusDto.getTotalConsumerCount() > 10) {
                log.info("系统回调通知 通知次数大于10次 停止回调 payOrderNo:{}", orderStatusDto.getOrderNo());
                return;
            }
            orderStatusDto.setTotalConsumerCount(orderStatusDto.getTotalConsumerCount() + 1);
            orderStatusDto.setDelaySendTime(System.currentTimeMillis());
            log.info("系统回调通知 payOrderNo:{},noticeNum:{}", orderStatusDto.getOrderNo(), orderStatusDto.getTotalConsumerCount());
            extRocketMQTemplate.sendDelay(orderStatusDto.getTotalConsumerCount(), MqConstant.MERCHANT_ORDER_NOTIFY_TOPIC, orderStatusDto);
        }
        catch (Exception e) {
            log.error("mq 发送异常:{}", e.getMessage(), e);
        }
    }

    boolean checkNotifyUrl(String notifyUrl) {
        return StringUtils.hasText(notifyUrl) && notifyUrl.startsWith("http");
    }

    /**
     * 转账订单回调
     * 
     * @param orderStatusDto
     * @param orderTransferDO
     * @param orderNotifyDO
     */
    public void notifyOrderTransfer(OrderStatusDto orderStatusDto, OrderTransferDO orderTransferDO, OrderNotifyDO orderNotifyDO) {
        if (orderTransferDO == null) {
            log.info("转账订单数据错误 停止回调");
            return;
        }
        if (!checkNotifyUrl(orderTransferDO.getNotifyUrl())) {
            log.info("转账订单未填写回调地址 停止回调 paymentId:{}", orderTransferDO.getPayOrderNo());
            return;
        }
        OrderNotifyDO notifyDO = orderNotifyGateway.notifyOrderTransfer(orderTransferDO);
        if (orderNotifyDO == null) {
            orderNotifyDO = orderNotifyService.queryDetail(orderTransferDO.getPayOrderNo(), PayOrderEnums.ORDER_STATUS_TYPE.TRANSFER_ORDER_STATUS.getCode());
        }
        if (orderNotifyDO == null) {
            notifyDO.setMchOrderNo(orderTransferDO.getMchOrderNo());
            notifyDO.setPayOrderNo(orderTransferDO.getPayOrderNo());
            notifyDO.setNotifyUrl(orderTransferDO.getNotifyUrl());
            notifyDO.setSn(orderTransferDO.getSn());
            notifyDO.setAppId(orderTransferDO.getAppId());
            notifyDO.setNotifyNum(1);
            notifyDO.setNotifyType(PayOrderEnums.ORDER_STATUS_TYPE.PAYMENT_ORDER_STATUS.getCode());
            orderNotifyService.addOrderNotify(notifyDO);
        }
        else {
            notifyDO.setId(orderNotifyDO.getId());
            notifyDO.setNotifyNum(orderNotifyDO.getNotifyNum() + 1);
            orderNotifyService.updateOrderNotify(notifyDO);
        }
        if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(notifyDO.getNotifyState())) {
            if (orderStatusDto == null) {
                retryNotify(orderTransferDO.getPayOrderNo(), notifyDO.getNotifyNum(), PayOrderEnums.ORDER_STATUS_TYPE.TRANSFER_ORDER_STATUS);
            }
            else {
                retryNotify(orderStatusDto);
            }
        }
    }

    /**
     * 提现订单回调
     * 
     * @param orderStatusDto
     * @param orderWithdrawDO
     * @param orderNotifyDO
     */
    public void notifyOrderWithdraw(OrderStatusDto orderStatusDto, OrderWithdrawDO orderWithdrawDO, OrderNotifyDO orderNotifyDO) {
        if (orderWithdrawDO == null) {
            log.info("提现订单数据错误 停止回调");
            return;
        }
        if (!checkNotifyUrl(orderWithdrawDO.getNotifyUrl())) {
            log.info("提现订单未填写回调地址 停止回调 paymentId:{}", orderWithdrawDO.getPayOrderNo());
            return;
        }
        OrderNotifyDO notifyDO = orderNotifyGateway.notifyOrderWithdraw(orderWithdrawDO);
        if (orderNotifyDO == null) {
            orderNotifyDO = orderNotifyService.queryDetail(orderWithdrawDO.getPayOrderNo(), PayOrderEnums.ORDER_STATUS_TYPE.WITHDRAW_ORDER_STATUS.getCode());
        }
        if (orderNotifyDO == null) {
            notifyDO.setMchOrderNo(orderWithdrawDO.getMchOrderNo());
            notifyDO.setPayOrderNo(orderWithdrawDO.getPayOrderNo());
            notifyDO.setNotifyUrl(orderWithdrawDO.getNotifyUrl());
            notifyDO.setSn(orderWithdrawDO.getSn());
            notifyDO.setAppId(orderWithdrawDO.getAppId());
            notifyDO.setNotifyNum(1);
            notifyDO.setNotifyType(PayOrderEnums.ORDER_STATUS_TYPE.PAYMENT_ORDER_STATUS.getCode());
            orderNotifyService.addOrderNotify(notifyDO);
        }
        else {
            notifyDO.setId(orderNotifyDO.getId());
            notifyDO.setNotifyNum(orderNotifyDO.getNotifyNum() + 1);
            orderNotifyService.updateOrderNotify(notifyDO);
        }
        if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(notifyDO.getNotifyState())) {
            if (orderStatusDto == null) {
                retryNotify(orderWithdrawDO.getPayOrderNo(), notifyDO.getNotifyNum(), PayOrderEnums.ORDER_STATUS_TYPE.WITHDRAW_ORDER_STATUS);
            }
            else {
                retryNotify(orderStatusDto);
            }
        }
    }
}
